package com.weng.coder.service;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.StringWriter;
import java.util.*;


import cn.hutool.core.util.ZipUtil;
import com.weng.coder.common.utils.Constants;
import com.weng.coder.common.utils.DBType;
import com.weng.coder.entity.*;
import com.weng.coder.service.generateCode.FreemarkerProccesor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.weng.coder.common.model.File;
import com.weng.coder.common.utils.NameConvertUtils;
import com.weng.coder.mapper.FieldMapper;


/**
 * 代码服务处理
 *
 * @version 
 * @author wengzhonghui  2017年7月12日 下午3:48:32
 * 
 */
@Service("codeService")
public class CodeServiceImpl implements CodeService {

    @Autowired
    private TemplateService templateService;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private NameRuleService nameRuleService;
    @Autowired
    private CodeTableService codeTableService;
    @Autowired
    private FieldService fieldService;
		@Autowired
    private ICoderConditionService coderConditionService;
    @Autowired
    private FreemarkerProccesor contentFreemarkerProcessor;

    @Override
    public Map<String,Object> generateCodeFile( String[] templateIds, String[] tableIds,String baseFilePath
    		,String isCatalog ,String username){
    	String fileName = System.currentTimeMillis()+"";//随机生成压缩包文件包
    	String fileTemp = baseFilePath + java.io.File.separator + fileName;
    	String isGenerate = "0";
    	StringBuilder existsClasss = new StringBuilder();
    	for (String templateId : templateIds) {
					 Template template = this.templateService.getOne(templateId);
					 Project project = this.projectService.getOne(template.getProjectId());
	         for (String tableId : tableIds) {
	        	 Map<String, String> result = generateCodeFileByTemplateAndTableId(
	        			  tableId, project, template, username, fileTemp, project.getIsCatalog()+"");
	        	 if(result!=null){
	        		 if(result.get("isGenerate")!=null && "1".equalsIgnoreCase(result.get("isGenerate"))){
	        			 isGenerate = "1";
	        		 }
	        		 if(result.get("existsClasss")!=null && result.get("existsClasss").length()>0){
	        			 if(existsClasss.length()>0){
	        				 existsClasss.append(",");
	        			 }
	        			 existsClasss.append(result.get("existsClasss"));
	        		 }
	        	 }
	         }
	    }
    	java.io.File tarZip = ZipUtil.zip(fileTemp);
		Map<String, Object> reMap = new HashMap<String, Object>();
		reMap.put("path", fileName + ".zip");
		reMap.put("existsClasss", existsClasss.toString());
		reMap.put("isGenerate",isGenerate);
		reMap.put("tarZip",tarZip);
        return reMap;
    }
    
    public String generateCodeFileByAll( String[] templateIds, String[] tableIds,String tarFile
    		,String isCatalog,String username ){
    	StringBuilder existsClasss = new StringBuilder();
    	for (String templateId : templateIds) {
			Template template = this.templateService.getOne(templateId);
			Project project = this.projectService.getOne(template.getProjectId());
	         for (String tableId : tableIds) {
	        	 Map<String, String> result = generateCodeFileByTemplateAndTableId( tableId, project
	        			 , template, username, tarFile, isCatalog);
	        	 if(result!=null){
	        		 if(result.get("existsClasss")!=null && result.get("isGenerate").length()>0){
	        			 if(result.get("existsClasss")!=null && result.get("existsClasss").length()>0){
		        			 if(existsClasss.length()>0){
		        				 existsClasss.append(",");
		        			 }
		        			 existsClasss.append(result.get("existsClasss"));
		        		 }
	        		 }
	        	 }
	         }
	    }
    	return existsClasss.toString();
    }
    
    /**
     * 根据模板和表生成代码
     * 
     * @param tableId
     * @param project
     * @param template
     * @param tarPath 生成的目标路径
     * @param isCatalog
     * @return
     */
    public Map<String,String> generateCodeFileByTemplateAndTableId(String tableId
    		,Project project,Template template,String userName,String tarPath,String isCatalog){
    	Map<String, String> reMap = new HashMap<String, String>();
    	String existsClasss = null;
    	String isGenerate = "0";
   	 	CodeTable table = this.codeTableService.getOne(tableId);
   	 	String domain = "";
        if(table.getEntityName()!=null && table.getEntityName().length()>0){
        	domain = table.getEntityName();
        }else{
        	domain = this.nameRuleService.getDomainName(project.getId(), tableId);
        }
   	 
        /* 判断新生成的类在Base项目里是否已经存在，如果已经存在则不生成*/
        boolean isFilter = false; 
        
        if(isFilter){
        	reMap.put("existsClasss", existsClasss);
    		reMap.put("isGenerate",isGenerate);
    		return reMap;
        }
        isGenerate = "1";
        File file = new File();
        file.setName(template.getFilename());
        file.setContent(template.getContent());
        String pkgName = getParsedPkgName(template, project, table.getArea());
   	 
   	 	  String path = getPath(template, project, table, domain);
        String name  = getName(domain, template, table);
        String content = getGeneratedCode(project, template, file, table, userName, tableId, pkgName);
        path = tarPath + java.io.File.separator + path ;
       
        String filePath = "";
        if("0".equalsIgnoreCase(isCatalog)){
        	if(name.indexOf("java")>=0 || name.indexOf("xml")>=0){// 生成的文件区分前后端文件夹
        		tarPath += java.io.File.separator + "backEnd";
       	 	}else {
       	 		tarPath += java.io.File.separator + "frontEnd";
       	 	}
        	java.io.File folderFile = new java.io.File(tarPath);
       	 	if(!folderFile.exists()){
       	 		folderFile.mkdirs();
            }
       	 	
       	 	filePath = tarPath +  java.io.File.separator + name;;
        }else{
       	 	java.io.File folderFile = new java.io.File(path);
            if(!folderFile.exists()){
           	 	folderFile.mkdirs();
            }
            filePath = path + java.io.File.separator + name;
        }
        contentToTxt(filePath, content);
    
        reMap.put("existsClasss", existsClasss);
		reMap.put("isGenerate",isGenerate);
		return reMap;
    }
    
    public String generateCodeFileByTemplateAndTableId(String tableId,String templateId,String userName){
   	 	CodeTable table = this.codeTableService.getOne(tableId);
   	 	Template template = this.templateService.getOne(templateId);
			Project project = this.projectService.getOne(template.getProjectId());
			File file = new File();
			file.setName(template.getFilename());
			file.setContent(template.getContent());
			String pkgName = getParsedPkgName(template, project, table.getArea());

			String content = getGeneratedCode(project, template, file, table, userName, tableId, pkgName);
		return content;
    }
    
    /**
     * 获取类路径全称
     * @param template
     * @param project
     * @param areaName
     * @return
     */
    public String getParsedPkgName(Template template,Project project,String areaName) {
        String suffix = template.getPkg();
        suffix = suffix==null ? "" : suffix;
        String companyCode = project.getCompanyCode();
        if(companyCode!=null){
        	suffix = suffix.replace("{company}", companyCode);
        }
        String projectPkg = project.getPkg();
        if(StringUtils.isNotEmpty(projectPkg)){
        	suffix = suffix.replace("{pkg}", projectPkg);
        }
        if(StringUtils.isNotEmpty(project.getCode())){
        	suffix = suffix.replace("{project}", project.getCode());
        }
        if(areaName==null){
        	suffix = suffix.replace(".{area}", "");
        }else{
        	suffix = suffix.replace("{area}", areaName);
        }
        return suffix;
    }
    
    /**
     * 把内容写入对应目录的文件
     * 
     * @param filePath
     * @param content
     */
    public static void contentToTxt(String filePath, String content) {  
        try {  
        	java.io.File f = new java.io.File(filePath);  
            if (!f.exists()) { 
            	 f.createNewFile();// 不存在则创建  
            }
            try(BufferedWriter output = new BufferedWriter(new FileWriter(f)); ){
							output.write(content);
						}

        } catch (Exception e) {
            e.printStackTrace();  
  
        }  
    }  
    
    public String getPath(Template template,Project project,CodeTable table,String domain) {
        String suffix = template.getPkg();
        if(suffix!=null){
        		if(project.getCode()!=null){
            	suffix = suffix.replace("{project}", project.getCode());
            }
            if(suffix!=null &&project.getCompanyCode()!=null){
            	suffix = suffix.replace("{company}", project.getCompanyCode());
            }
            if(suffix!=null && table.getArea()!=null){
            	suffix = suffix.replace("{area}", table.getArea());
            }
            domain = firstNameToLowerCase(domain);//首字母大写
            suffix = suffix.replace("{domain}", domain);
            suffix = suffix.replace("{domain_fl}", domain);
            suffix = suffix.replace(".", "/");
        }
        
        String modelName = template.getModualName();
        if(modelName!=null && project.getCode()!=null){
        	modelName = modelName.replace("{project}", project.getCode());
        }
        modelName = modelName==null ? "" : modelName;
        suffix = suffix==null ? "" : suffix;
        return modelName + "/" + suffix;
    }
    
    @Override
    public String getPath( String templateId, String tableId) {
        Template template = this.templateService.getOne(templateId);
        Project project = this.projectService.getOne(template.getProjectId());
        CodeTable table = this.codeTableService.getOne(tableId);
        String suffix = template.getPkg();
        if(project.getCode()!=null){
        	suffix = suffix.replace("{project}", project.getCode());
        }
        if(project.getCompanyCode()!=null){
        	suffix = suffix.replace("{company}", project.getCompanyCode());
        }
        if(table.getArea()!=null){
        	suffix = suffix.replace("{area}", table.getArea());
        }
        String domain = "";
        if(table.getEntityName()!=null && table.getEntityName().length()>0){
        	domain = table.getEntityName();
        }else{
        	domain = this.nameRuleService.getDomainName(project.getId(), tableId);
        }
        domain = firstNameToUpperCase(domain);//首字母大写
        suffix = suffix.replace("{domain}", domain);
        suffix = suffix.replace("{domain_fl}", domain);
        suffix = suffix.replace(".", "/");
        String modelName = template.getModualName();
        if(project.getCode()!=null){
        	modelName = modelName.replace("{project}", project.getCode());
        }
        return modelName + "/" + suffix;
    }

    public String getName(String domain,Template template,CodeTable table) {
				String methodName = table.getMethodName();
				methodName = methodName == null ? "": methodName;
        String prefix = template.getFilename();
        domain = firstNameToUpperCase(domain);//首字母大写
        String domain_firstToLow = firstNameToLowerCase(domain); //首字母小写
				methodName = firstNameToUpperCase(methodName);//首字母大写
				String methodName_firstToLow = firstNameToLowerCase(methodName); //首字母小写
        prefix = prefix.replace("{domain}", domain);
        prefix = prefix.replace("{domain_fl}", domain_firstToLow);
				prefix = prefix.replace("{table.methodName?cap_first}", methodName);
				prefix = prefix.replace("{table.methodName}", methodName_firstToLow);
        return prefix + "." + template.getExtension();
    }
    
    @Override
    public String getName( String templateId, String tableId) {
    	Template template = this.templateService.getOne(templateId);
        Project project = this.projectService.getOne(template.getProjectId());
        CodeTable table = this.codeTableService.getOne(tableId);
        String domain = "";
        String prefix = template.getFilename();
        if(table.getEntityName()!=null && table.getEntityName().length()>0){
        	domain = table.getEntityName();
        }else{
        	domain = this.nameRuleService.getDomainName(project.getId(), tableId);
        }
        domain = firstNameToUpperCase(domain);//首字母大写
        String domain_firstToLow = firstNameToLowerCase(domain); //首字母小写
        prefix = prefix.replace("{domain}", domain);
        prefix = prefix.replace("{domain_fl}", domain_firstToLow);
        return prefix + "." + template.getExtension();
    }
    
    @Override
    public String getGeneratedCode( String templateId, String tableId,String userName) {
    	Template template = this.templateService.getOne(templateId);
        Project project = this.projectService.getOne(template.getProjectId());
        CodeTable table = this.codeTableService.getOne(tableId);
        String pkgName = getParsedPkgName(template,project,table.getArea());
        File file = new File();
        file.setName(template.getFilename());
        file.setContent(template.getContent());
        return getGeneratedCode(project, template,file, table, userName, tableId, pkgName);
    }
    
    
    public String getGeneratedCode(Project project,Template template,File file
    		,CodeTable table,String username,String tableId,String pkgName) {

        List<Field> fileds = this.fieldService.findByTableId(tableId);
				List<CoderCondition> conditions = this.coderConditionService.findByTableId(tableId);

				fileds = fileds == null ? new ArrayList<>() : fileds;
				conditions = conditions == null ? new ArrayList<>() : conditions;
//        List<ColumnEntity> columns = this.columnDao.findByTableId(tableId);

        Map<String,Object> map = new HashMap<String,Object>();
       
        String domain = "";
        if(table.getEntityName()!=null && table.getEntityName().length()>0){
        	domain = table.getEntityName();
        }else{
        	domain = this.nameRuleService.getDomainName(project.getId(), tableId);
        }
        String javaTypeOfKey = "String";
        String priKeyName = "";
        if(fileds!=null && fileds.size()>0){
        	for(Field field : fileds){
        		if(field!=null && field.getIsPrimary()== Constants.FLAG_TRUE){
        			javaTypeOfKey = field.getJavaType();
        			priKeyName = field.getName();
        		}
        	}
        }
        convertJdbcTypeToMybatis(fileds);//对jdbcType根据mybatis的规则进行转换
        domain = firstNameToUpperCase(domain);//首字母大写
        String domain_firstToLow = firstNameToLowerCase(domain); //首字母小写
        String area = table.getArea()==null?"system":table.getArea();
        if(StringUtils.isEmpty(username)){
        	username = "wengzhonghui";
        }
        String jsArea =getJsArea(area);
        String urlArea = getUrlArea(area);
        //字符串参数
        map.put("pkg", project.getPkg());//项目包基础路径
        map.put("author", username);//作者
        map.put("company", project.getCompanyCode());//公司编码
        map.put("project", project.getCode());//项目编码
        map.put("area", area);//所属区域
        map.put("js_area", jsArea);//所属区域在前端的格式，例如area为api.manager时,在java中表现为包名，是对的，到前端JS要转为包名，需要改为apiManager
        map.put("url_area", urlArea);//所属区域在前端的格式，例如area为api.manager时,在java中表现为包名，是对的，到前端URL，需要改为api-manager
        map.put("project_api_prefix", getApiPrefix(project));//前端api请求前缀,如/user-center
        map.put("packageName", pkgName);//包路径
        map.put("domain", domain);//实体名，省字母大写
        map.put("domain_url", NameConvertUtils.camelToMiddleline(domain_firstToLow));//实体对应的请求URl，比如userCenter 转为user-center
        map.put("domain_fl", domain_firstToLow);//实体名首字母小写
        map.put("domain_firstToLow", domain_firstToLow);
        map.put("javaTypeOfKey", javaTypeOfKey);//主键Java类型
        map.put("priKeyName", priKeyName);//主键名称
        
        //对象参数
        map.put("table", table);
        map.put("fields", fileds);
        map.put("conditions",conditions);
//        map.put("columns", columns);
        map.put("dbTypes", Arrays.asList(DBType.values()));
        StringWriter writer = new StringWriter();
        this.contentFreemarkerProcessor.processTemplate(file, map, writer);
        String codeResut = writer.toString();
        codeResut = codeResut.replaceAll("@@@", "\\$");//模板中因为$字符中freemarker中特定使用的，用@@@代替
        return codeResut;
    }
    
    private static String getApiPrefix(Project project){
    	if(project!=null && !StringUtils.isEmpty(project.getApiPrefix())){
    		return project.getApiPrefix();
    	}else{
    		return "";
    	}
    }
    
    //对jdbcType根据mybatis的规则进行转换
    private static void convertJdbcTypeToMybatis(List<Field> fileds){
    	if(fileds!=null && fileds.size()>0){
    		for(Field filed : fileds){
    			convertJdbcTypeToMybatis(filed);
    		}
    	}
    	
    }
    private static void convertJdbcTypeToMybatis(Field filed){
    	if(filed!=null){
    		String jdbcType = filed.getJdbcType();
    		if(StringUtils.isEmpty(jdbcType)){
    			jdbcType = "VARCHAR";
    		}else if("int".equalsIgnoreCase(jdbcType)){
				jdbcType = "INTEGER";
			}else if("datetime".equalsIgnoreCase(jdbcType)){
				jdbcType = "DATE";
			} 
    		jdbcType = jdbcType.toUpperCase();
    		filed.setJdbcType(jdbcType);
    	}
    }
    
    
    //首字母大写
    public static String firstNameToUpperCase(String name) {
    		if(StringUtils.isEmpty(name)){
					return "";
				}
        name = name.substring(0, 1).toUpperCase() + name.substring(1);
       return  name;
      
    }
    //首字母小写
    public static String firstNameToLowerCase(String name) {
			if(StringUtils.isEmpty(name)){
    		return "";
    	}
        name = name.substring(0, 1).toLowerCase() + name.substring(1);
       return  name;
      
    }

    /**
     * 例如把api.manager转化为apiManager
     * @param area
     * @return
     */
    public static String getJsArea(String area){
    	String jsArea = area;
        try {
        	if(jsArea.indexOf(".")>0 ){//例如把api.manager转化为apiManager
        		StringBuffer jsAreaBuffer = new StringBuffer("");
        		String[] jsAreaList = jsArea.split("\\.");
        		for(String strTemp : jsAreaList){
        			if(!StringUtils.isEmpty(strTemp)){
        				jsAreaBuffer.append(firstNameToUpperCase(strTemp));
        			}
        		}
        		jsArea = jsAreaBuffer.toString();
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
        return firstNameToLowerCase(jsArea);
    }
    
    /**
     * 例如把模块名为api.manager转化为api-manager
     * @param area
     * @return
     */
    public static String getUrlArea(String area){
    	String jsArea = area;
        try {
        	if(jsArea.indexOf(".")>0 ){//例如把api.manager转化为apiManager
        		jsArea = jsArea.replace(".", "-");
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
        return firstNameToLowerCase(jsArea);
    }
    
    public static void main(String[] args){
    	System.out.println("api.manager".replace(".", "-"));
    }
}
